#pragma once
#include "..\Common\Global.h"
#include "Parser_Input.h"
#include "Parser_Output.h"

class Parser_Type;
class Parser_Str;
class Parser_Combinator_Node;

typedef Combinator<CParser_Input,CParser_Output> Parser_Combinator;

typedef BOOL(*ParserFunction)();

class Parser_Type : public Parser_Combinator
{
public:
	enum TYPE
	{
		ttSymbol,
		ttString,
		ttNumber,
		ttOperator,
		ttNote,
		ttSpace,
		ttEnter,
	};

	Parser_Type(TYPE _Type,BOOL _Not = FALSE);

	virtual CParser_Output Parser(CParser_Input& input);
protected:
	TYPE Type;
	BOOL Not;
};

class Parser_Str : public Parser_Combinator
{
public:
	Parser_Str(LPTSTR _value,BOOL _Not = FALSE);

	virtual CParser_Output Parser(CParser_Input& input);
protected:
	LPTSTR value;
	BOOL Not;
};

class Parser_Combinator_Node : public Combinator_Node<CParser_Input,CParser_Output>
{
public:
	Parser_Combinator_Node();
	Parser_Combinator_Node(Combinator<CParser_Input,CParser_Output>* _value) : theFunction(0),Combinator_Node<CParser_Input,CParser_Output>(_value){}
	Parser_Combinator_Node(Parser_Combinator_Node& _value) : theFunction(0),Combinator_Node<CParser_Input,CParser_Output>(_value){}

	Parser_Combinator_Node& operator[](ParserFunction _theFunction)
	{
		theFunction = _theFunction;
		return *this;
	}

	virtual CParser_Output Parser(CParser_Input& input);

	Parser_Combinator_Node& operator+(Parser_Combinator_Node& _value)
	{
		Combinator_Seq<CParser_Input,CParser_Output>* pSeq = new Combinator_Seq<CParser_Input,CParser_Output>(*this,_value,GetMM());
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(pSeq);
		GetMM()->AddSeq(pSeq);
		GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}

	Parser_Combinator_Node& operator|(Parser_Combinator_Node& _value)
	{
		Combinator_Alt<CParser_Input,CParser_Output>* pAlt = new Combinator_Alt<CParser_Input,CParser_Output>(*this,_value,GetMM());
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(pAlt);
		GetMM()->AddAlt(pAlt);
		GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}

	Parser_Combinator_Node& operator&(Parser_Combinator_Node& _value)
	{
		Combinator_And<CParser_Input,CParser_Output>* pAnd = new Combinator_And<CParser_Input,CParser_Output>(*this,_value,GetMM());
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(pAnd);
		GetMM()->AddAnd(pAnd);
		GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}

	Parser_Combinator_Node& operator*()
	{
		Combinator_Any<CParser_Input,CParser_Output>* pAny = new Combinator_Any<CParser_Input,CParser_Output>(*this,0,GetMM());
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(pAny);
		GetMM()->AddAny(pAny);
		GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}

	Parser_Combinator_Node& operator+()
	{
		Combinator_Any<CParser_Input,CParser_Output>* pAny = new Combinator_Any<CParser_Input,CParser_Output>(*this,0,GetMM());
		Parser_Combinator_Node* pNode1 = new Parser_Combinator_Node(pAny);
		Combinator_Seq<CParser_Input,CParser_Output>* pSeq = new Combinator_Seq<CParser_Input,CParser_Output>(*this,*pNode1,GetMM());
		Parser_Combinator_Node* pNode2 = new Parser_Combinator_Node(pSeq);
		GetMM()->AddAny(pAny);
		GetMM()->AddCombinatorNode(pNode1);
		GetMM()->AddSeq(pSeq);
		GetMM()->AddCombinatorNode(pNode2);
		return *pNode2;
	}

	static Parser_Combinator_Node& opt(Parser_Combinator_Node& _value)
	{
		Combinator_Opt<CParser_Input,CParser_Output>* pOpt = new Combinator_Opt<CParser_Input,CParser_Output>(_value,_value.GetMM());
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(pOpt);
		_value.GetMM()->AddOpt(pOpt);
		_value.GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}

	static Parser_Combinator_Node& not(Parser_Combinator_Node& _value)
	{
		Combinator_Not<CParser_Input,CParser_Output>* pNot = new Combinator_Not<CParser_Input,CParser_Output>(_value,_value.GetMM());
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(pNot);
		_value.GetMM()->AddNot(pNot);
		_value.GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}

	static Parser_Combinator_Node& clone(Parser_Combinator_Node& _value)
	{
		Parser_Combinator_Node* pNode = new Parser_Combinator_Node(_value);
		_value.GetMM()->AddCombinatorNode(pNode);
		return *pNode;
	}
protected:
	ParserFunction theFunction;
};